package com.lifang.framework.aop.aspectj;

import cn.hutool.core.lang.Assert;
import com.lifang.framework.aop.ClassFilter;
import com.lifang.framework.aop.MethodMatcher;
import com.lifang.framework.aop.Pointcut;
import com.lifang.framework.beans.BeansException;
import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.PointcutPrimitive;
import org.aspectj.weaver.tools.UnsupportedPointcutPrimitiveException;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

/**
 * aspectJ 切点
 * 维护 切点表达式、切点匹配、方法匹配等
 */
public class AspectJExpressionPointcut implements Pointcut, ClassFilter, MethodMatcher {

    /**
     * 支持的切点方式
     */
    private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<>();

    static {
        SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
    }

    /**
     * aspectJ切入点表达式
     */
    private final PointcutExpression pointcutExpression;

    /**
     * 以execution表达式的方式构造
     */
    public AspectJExpressionPointcut(String expression) {
        try {
            Assert.notBlank(expression);
            PointcutParser pointcutParser = PointcutParser.
                    getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, this.getClass().getClassLoader());
            this.pointcutExpression = pointcutParser.parsePointcutExpression(expression);
        } catch (UnsupportedPointcutPrimitiveException | IllegalArgumentException ex) {
            throw new BeansException("[" + expression + "] is not standard expression");
        }
    }

    /**
     * 判断目标class是否匹配
     */
    @Override
    public boolean matches(Class<?> clazz) {
        return pointcutExpression.couldMatchJoinPointsInType(clazz);
    }

    /**
     * 判断目标Class和目标方法是否匹配
     */
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        return pointcutExpression.matchesMethodExecution(method).alwaysMatches();
    }

    /**
     * 获取Class过滤器对象
     */
    @Override
    public ClassFilter getClassFilter() {
        return this;
    }

    /**
     * 获取method(方法)匹配对象
     */
    @Override
    public MethodMatcher getMethodMatcher() {
        return this;
    }

    public String getPointcutExpression() {
        return pointcutExpression.getPointcutExpression();
    }
}
